﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Reflection;
using System.Text;
using Antu.Core.Ajax;


namespace Antu.Core.Services
{
    /// <summary>
    /// json解析服务类
    /// </summary>
    public class SerializerService : AbstractService
    {
        #region 初始化
        internal SerializerService()
        {
            SerializableConverters = new Dictionary<Type, AbstractJavascriptConverter>();
            DeserializableConverters = new Dictionary<Type, AbstractJavascriptConverter>();
        }
        internal Dictionary<Type, AbstractJavascriptConverter> SerializableConverters;
        internal Dictionary<Type, AbstractJavascriptConverter> DeserializableConverters;
        #endregion

        #region 添加解析器
        internal void AddConverter(AbstractJavascriptConverter converter)
        {
            AddConverter(converter, false);
        }
        internal void AddConverter(AbstractJavascriptConverter converter, bool replace)
        {
            Type t;
            for (int i = 0; i < converter.SerializableTypes.Length; i++)
            {
                t = converter.SerializableTypes[i];

                if (this.SerializableConverters.ContainsKey(t))
                {
                    if (replace)
                    {
                        this.SerializableConverters[t] = converter;
                    }
                    continue;
                }

                this.SerializableConverters.Add(t, converter);
            }

            for (int i = 0; i < converter.DeserializableTypes.Length; i++)
            {
                t = converter.DeserializableTypes[i];

                if (this.DeserializableConverters.ContainsKey(t))
                {
                    if (replace)
                    {
                        this.DeserializableConverters[t] = converter;
                    }
                    continue;
                }
                this.DeserializableConverters.Add(t, converter);
            }
        }
        internal void AddDefaultConverter()
        {
            //这里加载默认的解析器，可以扩展
            AddConverter(new StringConverter());
            AddConverter(new PrimitiveConverter());
            AddConverter(new GuidConverter());
            AddConverter(new ExceptionConverter());
            AddConverter(new EnumConverter());
            AddConverter(new DecimalConverter());
            AddConverter(new NameValueCollectionConverter());
            AddConverter(new DateTimeConverter());
            AddConverter(new DataSetConverter());
            AddConverter(new DataTableConverter());
            AddConverter(new DataViewConverter());
            AddConverter(new IJavaScriptObjectConverter());
            AddConverter(new IDictionaryConverter());
            AddConverter(new ListConverter());
            AddConverter(new HashtableConverter());
            AddConverter(new IEnumerableConverter());
            AddConverter(new DataRowConverter());
            AddConverter(new HtmlControlConverter());
        }
        #endregion

        #region 序列化
        /// <summary>
        /// 将.Net对象转换成JSON文本
        /// </summary>
        /// <param name="o"></param>
        public string Serialize(object o)
        {
            StringBuilder sb = new StringBuilder();
            Serialize(o, sb);
            return sb.ToString();
        }
        /// <summary>
        /// 将.Net对象转换成JSON文本
        /// </summary>
        public void Serialize(object o, StringBuilder sb)
        {
            if (o == null || o is System.DBNull)
            {
                sb.Append("null");
                return;
            }

            AbstractJavascriptConverter c = null;
            Type type = o.GetType();

            if (this.SerializableConverters.TryGetValue(type, out c))
            {
                c.Serialize(o, sb);
                return;
            }

            foreach (AbstractJavascriptConverter c2 in this.SerializableConverters.Values)
            {
                if (c2.TrySerializeValue(o, type, sb))
                    return;
            }

            try
            {
                SerializeCustomObject(o, sb);
                return;
            }
            catch (StackOverflowException)
            {
                throw new Exception(" stack overflow exception while trying to serialize type '" + type.Name + "'.");
            }
        }
        /// <summary>
        /// 将自定义对象转换成JSON
        /// </summary>
        /// <param name="o"></param>
        /// <param name="sb"></param>
        internal void SerializeCustomObject(object o, StringBuilder sb)
        {
            Type t = o.GetType();

            bool nsa = false;
            bool roa = false;

            foreach (object attr in t.GetCustomAttributes(true))
            {
                if (attr is AjaxNonSerializableAttribute)
                {
                    nsa = true;
                }
                else if (attr is AjaxNoTypeUsageAttribute)
                {
                    roa = true;
                }
            }

            bool b = true;

            sb.Append('{');
            /*
            if ( !roa )
            {
                roa = !Utility.Settings.IncludeTypeProperty;
            }
            **/
            if (!roa)
            {
                sb.Append("\"__type\":");
                JavaScriptUtil.QuoteString(t.AssemblyQualifiedName, sb);

                b = false;
            }

            foreach (FieldInfo fi in t.GetFields(BindingFlags.Public | BindingFlags.Instance))
            {
                if (
                    (!nsa && !fi.IsDefined(typeof(AjaxNonSerializableAttribute), true)) ||
                    (nsa && fi.IsDefined(typeof(AjaxPropertyAttribute), true))
                    )
                {
                    if (!b)
                    {
                        sb.Append(",");

                    }
                    JavaScriptUtil.QuoteString(fi.Name, sb);
                    sb.Append(':');
                    Serialize(fi.GetValue(o), sb);

                    b = false;
                }
            }

            foreach (PropertyInfo prop in t.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
            {
                MethodInfo mi = prop.GetGetMethod();
                if (mi != null && mi.GetParameters().Length <= 0)
                {
                    if (
                        (!nsa && !prop.IsDefined(typeof(AjaxNonSerializableAttribute), true)) ||
                        (nsa && prop.IsDefined(typeof(AjaxPropertyAttribute), true))
                        )
                    {
                        if (!b)
                        {
                            sb.Append(",");
                        }
                        JavaScriptUtil.QuoteString(prop.Name, sb);
                        sb.Append(':');
                        Serialize(mi.Invoke(o, null), sb);

                        b = false;
                    }
                }
            }

            sb.Append('}');
        }
        #endregion

        #region 反序列化
        /// <summary>
        /// 从JSON文本表示的Javascript对象解析成.Net对象
        /// </summary>
        /// <param name="json"></param>
        /// <param name="type"></param>
        public object DeserializeFromJson(string json, Type type)
        {
            JSONParser p = new JSONParser();
            IJavascriptObject o = p.GetJSONObject(json);

            return Deserialize(o, type);
        }
        /// <summary>
        /// 从JSON文本表示的Javascript对象解析成.Net对象
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        /// <typeparam name="T"></typeparam>
        public T DeserializeFromJson<T>(string json)
        {
            return (T)DeserializeFromJson(json, typeof(T));
        }
        /// <summary>
        /// 将IJavascriptObject对象解析成.Net对象
        /// </summary>
        /// <param name="o"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public object Deserialize(IJavascriptObject o, Type type)
        {
            if (o == null)
            {
                return null;
            }
            JavascriptObject jso = o as JavascriptObject;
            if (jso != null && jso.Contains("__type"))
            {
                Type t = Type.GetType(jso["__type"].ToString());
                if (type == null || type.IsAssignableFrom(t))
                    type = t;
            }

            AbstractJavascriptConverter c = null;
            if (DeserializableConverters.TryGetValue(type, out c))
            {
                return c.Deserialize(o, type);
            }

            object v;
            foreach (AbstractJavascriptConverter c2 in DeserializableConverters.Values)
            {
                if (c2.TryDeserializeValue(o, type, out v))
                    return v;
            }


            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                Type tval = type.GetGenericArguments()[0];
                object va = Deserialize(o, tval);
                object val = Convert.ChangeType(va, tval);

                return Activator.CreateInstance(type, val);
            }

            if (typeof(IJavascriptObject).IsAssignableFrom(type))
            {
                return o;
            }

            if (o is JavascriptObject)
            {
                return DeserializeCustomObject(o as JavascriptObject, type);
            }

            throw new NotImplementedException("The object of type '" + o.GetType().FullName + "' could not converted to type '" + type + "'.");
        }
        /// <summary>
        /// 将JavascriptObject转换成自定义对象
        /// </summary>
        /// <param name="o">The o.</param>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        internal object DeserializeCustomObject(JavascriptObject o, Type type)
        {
            object c = Activator.CreateInstance(type);

            MemberInfo[] members = type.GetMembers(BindingFlags.GetField | BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance);
            foreach (MemberInfo memberInfo in members)
            {
                if (memberInfo.MemberType == MemberTypes.Field)
                {
                    if (o.Contains(memberInfo.Name))
                    {
                        FieldInfo fieldInfo = (FieldInfo)memberInfo;

                        fieldInfo.SetValue(c, Deserialize((IJavascriptObject)o[fieldInfo.Name], fieldInfo.FieldType));
                    }
                }
                else if (memberInfo.MemberType == MemberTypes.Property)
                {
                    if (o.Contains(memberInfo.Name))
                    {
                        PropertyInfo propertyInfo = (PropertyInfo)memberInfo;

                        if (propertyInfo.CanWrite)
                            propertyInfo.SetValue(c, Deserialize((IJavascriptObject)o[propertyInfo.Name], propertyInfo.PropertyType), new object[0]);
                    }
                }
            }

            return c;
        }
        #endregion

        #region 加载卸载服务
        /// <summary>
        /// 初始化服务
        /// </summary>
        public override void InitializeService()
        {
            AddDefaultConverter();
            base.InitializeService();
        }
        /// <summary>
        /// 卸载服务
        /// </summary>
        public override void UnloadService()
        {
            SerializableConverters.Clear();
            DeserializableConverters.Clear();
            base.UnloadService();
        }
        #endregion
    }
}
